package com.xpec.c4.service.ioc.cglib;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.NoOp;

import com.xpec.c4.service.ioc.IocProxy;
import com.xpec.c4.service.ioc.ProxyType;

/**
 * Cglib的代理实现
 * 
 * @author lipeilin
 * 
 */
public class CglibProxy implements IocProxy {

	/**
	 * 
	 */
	private static final long serialVersionUID = 6369711663657334093L;
	
	/**
	 * 处理器集合
	 */
	private static final Map<Class<?>,Enhancer> enhancerMap = new HashMap<Class<?>, Enhancer>();
	
	/**
	 * 类集合
	 */
	private static final Map<Class<?>,Class<?>> doneClass = new HashMap<Class<?>, Class<?>>();

	@Override
	public boolean isProxy(Class<?> targetClass) {
		return Enhancer.isEnhanced(targetClass);
	}

	@Override
	public boolean isProxy(Object obj) {
		return isProxy(obj.getClass());
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> T createObject(Class<T> targetClass, Set<ProxyType> proxyTypes) {
		Enhancer e = getEnhancer(targetClass, proxyTypes);

		Object obj = e.create();
		return (T) obj;
	}

	@Override
	public Class<?> getRealClass(Class<?> targetClass) {
		if (isProxy(targetClass)) {
			return targetClass.getSuperclass();
		}
		return targetClass;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> T createObject(Class<T> targetClass, Set<ProxyType> proxyTypes,
			Class<?>[] argumentTypes, Object[] arguments) {
		Enhancer e = getEnhancer(targetClass, proxyTypes);

		Object obj = e.create(argumentTypes, arguments);

		return (T) obj;
	}

	/**
	 * 获得代理创建器
	 * 
	 * @param <T>
	 * @param targetClass
	 * @param proxyTypes
	 * @return
	 */
	private <T> Enhancer getEnhancer(Class<T> targetClass,
			Set<ProxyType> proxyTypes) {
		
		Enhancer e = enhancerMap.get(targetClass);
		
		if(e==null){
			e = new Enhancer();
			e.setSuperclass(targetClass);
			e.setCallbacks(new Callback[] { new CglibCommonInterceptor(proxyTypes),
					NoOp.INSTANCE });
			e.setCallbackFilter(new CglibCallbackFilter());
			
			enhancerMap.put(targetClass, e);
			
		}
		
		return e;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.xpec.c4.service.ioc.IocProxy#getProxyClass(java.lang.Class)
	 */
	@Override
	public Class<?> getProxyClass(Class<?> targetClass,
			Set<ProxyType> proxyTypes) {
		Class<?> clazz = doneClass.get(targetClass);
		if(clazz==null){
			Object obj = createObject(targetClass, proxyTypes);
			clazz = obj.getClass();
			doneClass.put(targetClass, clazz);
		}
		return clazz;
	}

}

/**
 * Cglib的CallbackFilter
 * 
 * @author lipeilin
 * 
 */
class CglibCallbackFilter implements CallbackFilter {

	/*
	 * (non-Javadoc)
	 * 
	 * @see net.sf.cglib.proxy.CallbackFilter#accept(java.lang.reflect.Method)
	 */
	@Override
	public int accept(Method method) {
		// 只有是canaan包下的类，或都是公开的方法，才做代理
		// System.out.println(method);
		if (method.getDeclaringClass().getName().contains("com.xpec")
				&& Modifier.isPublic(method.getModifiers())) {

			// 如果是set函数，则不用代理
			if (method.getName().startsWith("set")
					|| method.getName().startsWith("is")) {
				return 1;
			}
			// 否则使用代理
			else {
				return 0;
			}
		}
		// 不做方法代理
		return 1;
	}

}
